//
//  node.cpp
//  cobalt
//
//  Created by Nicolas Godbout on 2013-09-01.
//  Copyright (c) 2013 Nicolas Godbout. All rights reserved.
//

#include "node.h"

#include <string>

namespace rdf{
    
    const char* str_BlankNode   = "BlankNode";
    const char* str_NamedNode   = "NamedNode";
    const char* str_Literal     = "Literal";
    const char* str_LangString  = "LangString";
    
    bool
    RDFNode::operator==(RDFNode const& other) const {
        if ( !node )
            return ! other.node;
        else if ( node->interfaceName == str_BlankNode ) {
            if ( other.node->interfaceName == str_BlankNode )
                return BlankNode(*this) == BlankNode(other);
            else
                return false;
        } else if ( node->interfaceName == str_NamedNode ) {
            if ( other.node->interfaceName == str_NamedNode )
                return NamedNode(*this) == NamedNode(other);
            else
                return false;
        } else if ( node->interfaceName == str_Literal || node->interfaceName == str_LangString ) {
            if ( other.node->interfaceName == str_Literal || other.node->interfaceName == str_LangString)
                return Literal(*this) == Literal(other);
            else
                return false;
        } else
            return false;
    }
    
    bool
    Literal::operator==(Literal const& other) const {
        if ( node->interfaceName == str_Literal ) {
            if ( other.node->interfaceName == str_Literal )
                return node->datatype == other.node->datatype && std::strcmp(node->nominalValue, other.node->nominalValue) == 0;
            else
                return false;
        } else if ( node->interfaceName == str_LangString ) {
            if ( other.node->interfaceName == str_LangString )
                return strcmp(node->lang, other.node->lang) == 0 && strcmp(node->nominalValue, other.node->nominalValue) == 0;
            else
                return false;
        }
        return false;
    }
    
    /* Comparison with wildcard semantics: empty Node is equal to everything else */
    bool
    RDFNode::operator<(RDFNode const& other) const {
//        if ( !node ) {
//            if ( !other.node )
//                return false;
//            else
//                return true;
        if ( !node || !other.node )
            return false;
        else if ( node->interfaceName == str_BlankNode ) {
            if ( other.node->interfaceName == str_BlankNode )
                return BlankNode(*this) < BlankNode(other);
//            else if ( !other.node )
//                return false;
            else
                return true;
        } else if ( node->interfaceName == str_NamedNode ) {
            if ( other.node->interfaceName == str_NamedNode )
                return NamedNode(*this) < NamedNode(other);
            else if ( other.node->interfaceName == str_Literal || other.node->interfaceName == str_LangString )
                return true;
            else
                return false;
        } else if ( node->interfaceName == str_Literal || node->interfaceName == str_LangString ) {
            if ( other.node->interfaceName == str_Literal || other.node->interfaceName == str_LangString )
                return Literal(*this) < Literal(other);
            else
                return false;
        } else
            throw;
    }
    
    bool
    Literal::operator<(Literal const& other) const {
        if ( node->interfaceName == str_Literal ) {
            if ( other.node->interfaceName == str_Literal ) {
                if ( node->datatype < other.node->datatype )
                    return true;
                else if ( node->datatype == other.node->datatype )
                    return strcmp(node->nominalValue, other.node->nominalValue) < 0;
                else
                    return false;
            } else
                return true;
        } else if ( node->interfaceName == str_LangString ) {
            if ( other.node->interfaceName == str_LangString ) {
                int cmp = strcmp(node->lang, other.node->lang);
                if ( cmp < 0 )
                    return true;
                else if ( cmp == 0 )
                    return strcmp(node->nominalValue, other.node->nominalValue) < 0;
                else
                    return false;
            } else
                return false;
        } else
            throw;
    }
    
    std::string
    RDFNode::toNT() const {
        if ( !node )
            return std::string();
        else if ( node->interfaceName == str_BlankNode )
            return BlankNode(*this).toNT();
        else if ( node->interfaceName == str_NamedNode )
            return NamedNode(*this).toNT();
        else if ( node->interfaceName == str_Literal || node->interfaceName == str_LangString )
            return Literal(*this).toNT();
        else
            throw;
    }
    
    std::string
    BlankNode::toNT() const {
        return std::string("_:") + node->nominalValue;
    }
    
    std::string
    NamedNode::toNT() const {
        return '<' + std::string(node->nominalValue) + '>';
    }
    
    std::string
    Literal::toNT() const {
        if ( node->interfaceName == str_Literal )
            return '"' + std::string(node->nominalValue) + "\"^^" + node->datatype.toNT();
        else if ( node->interfaceName == str_LangString )
            return '"' + std::string(node->nominalValue) + "\"@" + std::string(node->lang);
        else
            throw;
    }
    
} // namespace rdf